package com.ruoyi.ucar.wxpay.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.annotations.SerializedName;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.AuthTypeEnum;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.AesUtil;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ucar.boreq.OrderSignQueryBoReq;
import com.ruoyi.ucar.boreq.UcarOrderUpdateStatusBoReq;
import com.ruoyi.ucar.boresp.CustomerSignBoResq;
import com.ruoyi.ucar.boresp.OrderSignBoResq;
import com.ruoyi.ucar.common.CommonVoResp;
import com.ruoyi.ucar.common.ResultEnum;
import com.ruoyi.ucar.domain.*;
import com.ruoyi.ucar.mapper.TCustomerMapper;
import com.ruoyi.ucar.mapper.TRechargeRecordMapper;
import com.ruoyi.ucar.service.*;
import com.ruoyi.ucar.util.CommonUtil;
import com.ruoyi.ucar.util.NanoTimestampUtil;
import com.ruoyi.ucar.voreq.*;
import com.ruoyi.ucar.voresp.UCarOrderPayNotifyVoResp;
import com.ruoyi.ucar.voresp.UCarOrderRefundNotifyVoResp;
import com.ruoyi.ucar.voresp.UCarRechargeRecordPayNotifyVoResp;
import com.ruoyi.ucar.wxpay.entity.WxPayV3Bean;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.*;
import com.ijpay.wxpay.model.v3.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.signers.PlainDSAEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.*;
import okhttp3.OkHttpClient;
import javax.crypto.Cipher;
import java.security.cert.CertificateFactory;
import java.util.Base64;
import java.util.HashMap;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.http.DefaultHttpClientBuilder;
import com.wechat.pay.java.core.http.HttpClient;
import com.wechat.pay.java.core.http.HttpHeaders;
import com.wechat.pay.java.core.http.HttpMethod;
import com.wechat.pay.java.core.http.HttpRequest;
import com.wechat.pay.java.core.http.HttpResponse;
import com.wechat.pay.java.core.http.JsonRequestBody;
import com.wechat.pay.java.core.http.MediaType;

/**
 * <p>U车查查询车辆就是好用，封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
 *
 * <p>不依赖任何第三方 mvc 框架，仅仅作为工具使用简单快速完成支付模块的开发，可轻松嵌入到任何系统里。 </p>
 */
@Controller
@RequestMapping("/ucar/wxPay")
@Api(value = "微信支付管理",tags = "微信支付模块接口")
public class WxPayV3Controller {
	private final Logger log = LoggerFactory.getLogger(this.getClass());
	private final static int OK = 200;

	@Autowired
	WxPayV3Bean wxPayV3Bean;

	@Autowired
	ITOrderService itOrderService;

	@Autowired
	ITWithdrawRecordService itWithdrawRecordService;

	@Autowired
	private ITOrderPayDetailService itOrderPayDetailService;

	@Autowired
	private TCustomerMapper tCustomerMapper;

	@Autowired
	private ITConsumeDataService itConsumeDataService;

	String serialNo;
	String platSerialNo;




	@RequestMapping("/getSerialNumber")
	@ResponseBody
	public String serialNumber() {
		return getSerialNumber();
	}

	@RequestMapping("/getPlatSerialNumber")
	@ResponseBody
	public String platSerialNumber() {
		return getPlatSerialNumber();
	}

	private String getSerialNumber() {
		if (StrUtil.isEmpty(serialNo)) {
			// 获取证书序列号
			X509Certificate certificate = PayKit.getCertificate(wxPayV3Bean.getCertPath());
			if (null != certificate) {
				serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
				// 提前两天检查证书是否有效
				boolean isValid = PayKit.checkCertificateIsValid(certificate, wxPayV3Bean.getMchId(), -2);
				log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
			}
//            System.out.println("输出证书信息:\n" + certificate.toString());
//            // 输出关键信息，截取部分并进行标记
//            System.out.println("证书序列号:" + certificate.getSerialNumber().toString(16));
//            System.out.println("版本号:" + certificate.getVersion());
//            System.out.println("签发者：" + certificate.getIssuerDN());
//            System.out.println("有效起始日期：" + certificate.getNotBefore());
//            System.out.println("有效终止日期：" + certificate.getNotAfter());
//            System.out.println("主体名：" + certificate.getSubjectDN());
//            System.out.println("签名算法：" + certificate.getSigAlgName());
//            System.out.println("签名：" + certificate.getSignature().toString());
		}
		System.out.println("serialNo:" + serialNo);
		return serialNo;
	}

	private String getPlatSerialNumber() {
		if (StrUtil.isEmpty(platSerialNo)) {
			// 获取平台证书序列号
			X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));
			platSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
		}
		System.out.println("platSerialNo:" + platSerialNo);
		return platSerialNo;
	}

	private String savePlatformCert(String associatedData, String nonce, String cipherText, String algorithm, String certPath) {
		try {
			String key3 = wxPayV3Bean.getApiKey3();
			String publicKey;
			if (StrUtil.equals(algorithm, AuthTypeEnum.SM2.getPlatformCertAlgorithm())) {
				publicKey = PayKit.sm4DecryptToString(key3, cipherText, nonce, associatedData);
			} else {
				AesUtil aesUtil = new AesUtil(wxPayV3Bean.getApiKey3().getBytes(StandardCharsets.UTF_8));
				// 平台证书密文解密
				// encrypt_certificate 中的  associated_data nonce  ciphertext
				publicKey = aesUtil.decryptToString(
					associatedData.getBytes(StandardCharsets.UTF_8),
					nonce.getBytes(StandardCharsets.UTF_8),
					cipherText
				);
			}
			if (StrUtil.isNotEmpty(publicKey)) {
				// 保存证书
				FileWriter writer = new FileWriter(certPath);
				writer.write(publicKey);
				// 获取平台证书序列号
				X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
				return certificate.getSerialNumber().toString(16).toUpperCase();
			}
			return "";
		} catch (Exception e) {
			log.error("保存平台证书异常", e);
			return e.getMessage();
		}
	}


	@RequestMapping("/platformCert")
	@ResponseBody
	public String platformCert() {
		try {
			String associatedData = "certificate";
			String nonce = "9bc94726a4d6";
			String cipherText="EOwUbwxVn0l/1c1XyzBGC2bzMlbwUGF7bPyIPlM9sh3vCm3R+WjJyx45buxhpTMmXtpOxmh1R2FWbhumnS3KJLy/qdNMSY2DRbqP0W3iJs4CC+b08MGgfZQcL5YFPQTbEphaxEtK6dhenjBsQ7CKa0SJf0VSX+71JxbdRTQH89cFiZCximIKvrnfaFH6lU6f1dRNVpJMSEGAO5yZwvegEvmXMlDXkGkXgXODJaN6KrUfjR0i6CLcEIc3dRUpIVlVHxUPwdIWdTqlFM1p6krL63EeHdk9lV4iorYjYy12g3dJKggGVFZjLxj9SBhoZ+WTcpkNBn6XeykcYQsSHLJdTI3nr9DB13ttuX+DL8HZ3An3EXX52aftp9qIA6iS2ld4IhwE9d/Kk4xqJsZMbz/iP1dB9P/WNAlNCZxIY7PnccAXuq+1k1pHvUJa+bLnC5KVCPKdKqkVKQFpFQ/8Oyhx7aXrRDE1EKJmeREpwLlXrwho9NXOmWRTwzf9JVnsZxvdqeGi6y12eIVjlnVjoh1F+YNUW3VxnSTK9JEsr+vvZqGgkIOpubEI1f9v38V+glRDOP9BIJDmBrxxBkNv4G6c58a2yqNiaAAAz70ZuCP8iTOVAOBIpvohWu8awzTnuDRyssQPxneNT1ntBWoDzEaRI8QSBVSlc8AZQJLMEMTf7w7Z7HKnaex4q14Wpv3w1PrR8uuy4PfLXMZxDk9drUV3TG2X2zdKm3OYGxLZ/ifAFmuSenKlMZmHdeP2dLU9HmY08mIsmy5AVa+oZx8MlvSHyWS8al/FHF9FS0gvxeiwXhFQE0drZyu/C7T7FFmiz1FnsuWboH/LOlKSW0C8zQyLHoznTNvPyqnEHXVgM/UBugZexMn6MieJcp/ywuzqfK1TeAvutNA/e1X8YCm/of2JlKPJDs1i8OD4WOeEAQgxnIEB/n2empYPEFLZMOYwnD03bpbOezrhROKrOt4YQEDth9Z4H/8pnzFH3mHiG3/TCARPCndXOkMJPag8ez6tIk7cF1Op9D2w08T8tStt3NdVd04QJWrNm2Cbs8h+mH2+Pk99ultmOAStQqzsU/YA7mdth6ih+lsa9vADhG7Vu3lD3DV35VCizJEPsEe82TcSV8WpxCUe79+bB4CDCcoRirFZpl5bfDMu9G754Z30v/ayw1CND0penb3IIkJgJTCh4+NKuNYtj+UUtFMFOQQrqFZnsOE/OeKm1UYXqdJpcBZBkVU7XliVCT+CaWXUE5bTZR+SBYllSlhxmFbUVQonRe07YhHVUuOFMw2fvhd+zPZIsKZOk/aFBoS2c6weK8wl3K3TK8QZ8gSTI0+FAmfRQVid8PauaiO0VmdGxLNIjCzEt7EOWE/q/ArcCZifWwLy79nWwFglV1LOX2qhhykwPSWVij1uQS0HHaUjUOWAKAOkIVqErMeGTFpRHlQPZvi0ItFEgd9hVWl2fQ44B4mpsHwuhpCCed3iw1JKcaILJZLslB9xKTuWQJM9zRx+AaTKKtPcZpcwe5cJO80FTqNxBJYVk1+75CnZt+YRS5YWEkyWfMpF+660uFn2vKZ5SrG5mBec9eEnavfVqsI8bT836Mi6aX6eOOwgndshEOl0RiTrg/GGv4j5tGo6TkU6sYzX+tA+f/5M3/bAIC2gca4RWfhynPWiDP/etQVVenx1jeaFhWRe257m4HrDOZAjWd9FELBkiMZA2XIplzZq3ZHZDDZrnaSJSIH/37VgZ+HrCsKPURi93D2zalcpxcILXRYCTbDLogjn03z/lYjVK4ezNx2C0zQ8gaIPzNcoALM6TFyjxJ+FvZtMu0KGSuDCCTpterCTdzL5m0ggLi3Vltf6XHm8DBSpg9QCol70ZHHlBKLUdRPHOwQdPg==";
			String serialNo="379528A91BB270CFBF7557C76679B07089482A7A";
			String algorithm = "AEAD_AES_256_GCM";
			return savePlatformCert(associatedData, nonce, cipherText, algorithm, wxPayV3Bean.getPlatformCertPath());
		} catch (Exception e) {
			log.error("保存平台证书异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/smPlatformCert")
	@ResponseBody
	public String smPlatformCert() {
		try {
			String associatedData = "certificate";
			String nonce = "";
			String cipherText = "";
			String algorithm = "AEAD_SM4_GCM";
			return savePlatformCert(associatedData, nonce, cipherText, algorithm, wxPayV3Bean.getPlatformCertPath());
		} catch (Exception e) {
			log.error("保存国密平台证书异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/get")
	@Anonymous
	@ResponseBody
	public String v3Get() {
		// 获取平台证书列表
		try {
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.GET,
				WxDomainEnum.CHINA.toString(),
				CertAlgorithmTypeEnum.getCertSuffixUrl(CertAlgorithmTypeEnum.ALL.getCode()),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				"",
				AuthTypeEnum.RSA.getCode()
			);
			Map<String, List<String>> headers = response.getHeaders();
			log.info("请求头: {}", headers);
			String timestamp = response.getHeader("Wechatpay-Timestamp");
			String nonceStr = response.getHeader("Wechatpay-Nonce");
			String serialNumber = response.getHeader("Wechatpay-Serial");
			String signature = response.getHeader("Wechatpay-Signature");

			String body = response.getBody();
			int status = response.getStatus();

			log.info("serialNumber: {}", serialNumber);
			log.info("status: {}", status);
			log.info("body: {}", body);
			int isOk = 200;
			if (status == isOk) {
				JSONObject jsonObject = JSONUtil.parseObj(body);
				JSONArray dataArray = jsonObject.getJSONArray("data");
				// 默认认为只有一个平台证书
				JSONObject encryptObject = dataArray.getJSONObject(0);
				JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
				String associatedData = encryptCertificate.getStr("associated_data");
				String cipherText = encryptCertificate.getStr("ciphertext");
				String nonce = encryptCertificate.getStr("nonce");
				String algorithm = encryptCertificate.getStr("algorithm");
				String serialNo = encryptObject.getStr("serial_no");
				final String platSerialNo = savePlatformCert(associatedData, nonce, cipherText, algorithm, wxPayV3Bean.getPlatformCertPath());
				log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo);
				// 根据证书序列号查询对应的证书来验证签名结果
				boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
				log.info("verifySignature:{}", verifySignature);
			}
			return body;
		} catch (Exception e) {
			log.error("获取平台证书列表异常", e);
			return null;
		}
	}

	@RequestMapping("/nativePay")
	@ResponseBody
	public String nativePay() {
		try {
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
				.setAppid(wxPayV3Bean.getAppId())
				.setMchid(wxPayV3Bean.getMchId())
				.setDescription("U车查查询车辆就是好用")
				.setOut_trade_no(PayKit.generateStr())
				.setTime_expire(timeExpire)
				.setAttach("芜湖咖博网络科技")
				.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
				.setAmount(new Amount().setTotal(1));

			log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.NATIVE_PAY.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(unifiedOrderModel),
				AuthTypeEnum.RSA.getCode()
			);
			log.info("统一下单响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			return response.getBody();
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/appPay")
	@ResponseBody
	public String appPay() {
		try {
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
				.setAppid(wxPayV3Bean.getAppId())
				.setMchid(wxPayV3Bean.getMchId())
				.setDescription("U车查查询车辆就是好用")
				.setOut_trade_no(PayKit.generateStr())
				.setTime_expire(timeExpire)
				.setAttach("芜湖咖博网络科技")
				.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
				.setAmount(new Amount().setTotal(1));

			log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.APP_PAY.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(unifiedOrderModel),
				AuthTypeEnum.RSA.getCode()
			);
			log.info("统一下单响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
//			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			// 微信支付公钥验证签名
			boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (response.getStatus() == OK && verifySignature) {
				String body = response.getBody();
				log.info("请求响应 {}", body);
				JSONObject jsonObject = JSONUtil.parseObj(body);
				String prepayId = jsonObject.getStr("prepay_id");
				Map<String, String> map = WxPayKit.appCreateSign(wxPayV3Bean.getAppId(), wxPayV3Bean.getMchId(), prepayId, wxPayV3Bean.getKeyPath());
				log.info("唤起支付参数:{}", map);
				return JSONUtil.toJsonStr(map);
			}
			return JSONUtil.toJsonStr(response);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}


	@RequestMapping("/query")
	@ResponseBody
	public String query(@RequestParam String outTradeNo) {
		try {
			Map<String, String> params = new HashMap<>(16);
			params.put("mchid", wxPayV3Bean.getMchId());

			log.info("统一下单参数 {}", JSONUtil.toJsonStr(params));
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.GET,
				WxDomainEnum.CHINA.toString(),
				String.format(BasePayApiEnum.ORDER_QUERY_BY_OUT_TRADE_NO.toString(), outTradeNo),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				params,
				AuthTypeEnum.RSA.getCode()
			);
			log.info("查询响应 {}", response);
			if (response.getStatus() == OK) {
				// 根据证书序列号查询对应的证书来验证签名结果
//				boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
				// 微信公钥验证签名
				boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
				log.info("verifySignature: {}", verifySignature);
				return response.getBody();
			}
			return JSONUtil.toJsonStr(response);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@Autowired
	private WxMaService wxMaService;

	@Autowired
	private ITCustomerService tCustomerService;

	@ApiOperation("微信小程序支付接口")
	@PostMapping("/jsApiPay")
	@ResponseBody
	public CommonVoResp<Map<String, String>> jsApiPay(
			@RequestBody OrderJsApiPayVoReq orderJsApiPayVoReq) {

		log.info("微信小程序支付接口入参 {}", orderJsApiPayVoReq);
		IJPayHttpResponse response =null;
		CommonVoResp<Map<String, String>> commonVoResp=new CommonVoResp<>();
		        CustomerSignBoResq customerSignBoResq= tCustomerService.judgeCustomerSign();
        if(StringUtils.isNull(customerSignBoResq)){
            commonVoResp.setCode(ResultEnum.CUSTOMERNODATA.getCode());
            commonVoResp.setMessage(ResultEnum.CUSTOMERNODATA.getMsg());
			log.info("微信小程序支付接口出参:{}",commonVoResp);
            return commonVoResp;
        }else{
            if (!customerSignBoResq.getSignFlag()) {
				OrderSignQueryBoReq orderSignQueryBoReq=new OrderSignQueryBoReq();
				orderSignQueryBoReq.setOrderCode(orderJsApiPayVoReq.getOrderCode());
				OrderSignBoResq orderSignBoResq=itOrderService.judgeOrderSign(orderSignQueryBoReq);
				if(StringUtils.isNull(orderSignBoResq)){
					commonVoResp.setCode(ResultEnum.ORDERNODATA.getCode());
					commonVoResp.setMessage(ResultEnum.ORDERNODATA.getMsg());
					log.info("微信小程序支付接口出参:{}",commonVoResp);
					return commonVoResp;
				}else{
					if (!orderSignBoResq.getSignFlag()) {
					  commonVoResp.setCode(ResultEnum.CUSTOMERNOSIGN.getCode());
					  commonVoResp.setMessage(ResultEnum.CUSTOMERNOSIGN.getMsg());
					  log.info("微信小程序支付接口出参:{}", commonVoResp);
					  return commonVoResp;
				   }
				}
            }
        }

		try {
			WxMaJscode2SessionResult session = wxMaService.getUserService()
					.getSessionInfo(orderJsApiPayVoReq.getCode());
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 30);
			int totalFeel=(orderJsApiPayVoReq.getTotalFeel().multiply(new BigDecimal("100"))).intValue();
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
				.setAppid(wxPayV3Bean.getAppId())
				.setMchid(wxPayV3Bean.getMchId())
				.setDescription(orderJsApiPayVoReq.getBody())
				.setOut_trade_no(orderJsApiPayVoReq.getOrderCode())
				.setTime_expire(timeExpire)
				.setAttach("U车查微信小程序")
				.setNotify_url(wxPayV3Bean.getDomain().concat("/ucar/wxPay/payNotify"))
				.setAmount(new Amount().setTotal(totalFeel).setCurrency("CNY"))
				.setPayer(new Payer().setOpenid(session.getOpenid()));

			log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
			  response = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.JS_API_PAY.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(unifiedOrderModel)
			);
			log.info("统一下单响应 {}", response);
			if(StringUtils.isNotNull(response)&&response.getStatus() != OK){
				Map<String, String> map =new HashMap<>();
				map.put("body",	response.getBody());
				map.put("status",new Integer(response.getStatus()).toString());
				commonVoResp.setCode(ResultEnum.WXPAYAPIERROR.getCode());
				commonVoResp.setMessage(ResultEnum.WXPAYAPIERROR.getMsg());
				commonVoResp.setData(map);
				log.info("微信小程序支付接口出参:{}",commonVoResp);
				return commonVoResp;
			}
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (response.getStatus() == OK && verifySignature) {
				UcarOrderUpdateStatusBoReq ucarOrderUpdateStatusBoReq=new UcarOrderUpdateStatusBoReq();
				ucarOrderUpdateStatusBoReq.setPayStatus("paying");
				ucarOrderUpdateStatusBoReq.setOrderCode(orderJsApiPayVoReq.getOrderCode());
				itOrderService.updateOrderStatus(ucarOrderUpdateStatusBoReq,null);
				String body = response.getBody();
				JSONObject jsonObject = JSONUtil.parseObj(body);
				String prepayId = jsonObject.getStr("prepay_id");
				Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), prepayId, wxPayV3Bean.getKeyPath());
				log.info("唤起支付参数:{}", map);
				commonVoResp.setData(map);
			}
			return commonVoResp;
		} catch (Exception e) {
			log.error("系统异常", e);
			if(StringUtils.isNull(response)){
				Map<String, String> map =new HashMap<>();
				map.put("body",	"微信支付响应内容为空！异常信息："+e.getLocalizedMessage());
				map.put("status","404");
				commonVoResp.setCode(ResultEnum.WXPAYAPIERROR.getCode());
				commonVoResp.setMessage(ResultEnum.WXPAYAPIERROR.getMsg());
				commonVoResp.setData(map);
				log.info("微信小程序支付接口出参:{}",commonVoResp);
				return commonVoResp;
			}else{
				Map<String, String> map =new HashMap<>();
				map.put("body",	e.getLocalizedMessage());
				map.put("status","500");
				commonVoResp.setCode(ResultEnum.WXPAYAPIERROR.getCode());
				commonVoResp.setMessage(ResultEnum.WXPAYAPIERROR.getMsg());
				commonVoResp.setData(map);
				log.info("微信小程序支付接口出参:{}",commonVoResp);
				return commonVoResp;
			}
		}
	}
	@Autowired
	private TRechargeRecordMapper tRechargeRecordMapper;



	@PostMapping(value = "/rechargeRecordPayNotify")
	@ResponseBody
	@Anonymous
	public UCarRechargeRecordPayNotifyVoResp rechargeRecordPayNotify(HttpServletRequest request) {
		UCarRechargeRecordPayNotifyVoResp  uCarRechargeRecordPayNotifyVoResp=new UCarRechargeRecordPayNotifyVoResp();
		Map<String, String> map = new HashMap<>(12);
		try {
			String timestamp = request.getHeader("Wechatpay-Timestamp");
			String nonce = request.getHeader("Wechatpay-Nonce");
			String serialNo = request.getHeader("Wechatpay-Serial");
			String signature = request.getHeader("Wechatpay-Signature");

			log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
			String result = HttpKit.readData(request);
			log.info("微信小程序充值支付成功支付通知密文 {}", result);
//			String plainText = null;
			// 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
			String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
					wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
			// 微信公钥验证签名并解密
//			if (StringUtils.equals(serialNo, wxPayV3Bean.getPublicKeyId())) {
//				plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
//					wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
//			}
			log.info("微信小程序充值支付成功支付通知明文 {}", plainText);

			if (StrUtil.isNotEmpty(plainText)) {
				// 3. 解密业务数据
				JSONObject json = JSONUtil.parseObj(plainText);
				String outTradeNo = json
						.getStr("out_trade_no");
				String transactionId = json
						.getStr("transaction_id");
				// 4. 处理充值记录逻辑
				TRechargeRecord tRechargeRecord=tRechargeRecordMapper.selectOne(new LambdaQueryWrapper<TRechargeRecord>().eq(TRechargeRecord::getRechargeRecordOrderCode,outTradeNo).eq(TRechargeRecord::getDeleteFlag,1l));
				tRechargeRecord.setTransactionId(transactionId);
				tRechargeRecord.setRechargeStatus("toAccount");
				tRechargeRecordMapper.updateById(tRechargeRecord);
				//5.更新客户的余额数据
				TCustomer tCustomer=tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>().eq(TCustomer::getCustomerUuid,tRechargeRecord.getCustomerUuid()).eq(TCustomer::getDeleteFlag,1l));
				tCustomer.setBalanceNumber(tCustomer.getBalanceNumber().add(tRechargeRecord.getRechargeMoney()));
				tCustomer.setGiftMoney(tCustomer.getGiftMoney().add(tRechargeRecord.getGiveMoney()));
				tCustomerMapper.updateById(tCustomer);
			} else {
				uCarRechargeRecordPayNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
				uCarRechargeRecordPayNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			}
			log.info("微信小程序充值支付成功后回调接口出参：{}", uCarRechargeRecordPayNotifyVoResp);
			return uCarRechargeRecordPayNotifyVoResp;
		} catch (Exception e) {
			log.error("微信小程序充值支付回调接口系统异常", e);
			uCarRechargeRecordPayNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
			uCarRechargeRecordPayNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			log.info("微信小程序充值支回调接口出参：{}", uCarRechargeRecordPayNotifyVoResp);
			return uCarRechargeRecordPayNotifyVoResp;
		}
	}

	@ApiOperation("微信小程序充值支付接口")
	@PostMapping("/rechargeRecordApiPay")
	@ResponseBody
	public CommonVoResp<Map<String, String>> rechargeRecordApiPay(
			@RequestBody RechargeRecordApiPayVoReq rechargeRecordApiPayVoReq) {

		log.info("微信小程序充值支付接口入参 {}", rechargeRecordApiPayVoReq);
		IJPayHttpResponse response =null;
		CommonVoResp<Map<String, String>> commonVoResp=new CommonVoResp<>();

		try {
			WxMaJscode2SessionResult session = wxMaService.getUserService()
					.getSessionInfo(rechargeRecordApiPayVoReq.getCode());
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 30);
			int totalFeel=(rechargeRecordApiPayVoReq.getTotalFeel().multiply(new BigDecimal("100"))).intValue();

			String rechargeRecordOrderCode= NanoTimestampUtil.getNanoTimestamp();
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
					.setAppid(wxPayV3Bean.getAppId())
					.setMchid(wxPayV3Bean.getMchId())
					.setDescription(rechargeRecordApiPayVoReq.getBody())
					.setOut_trade_no(rechargeRecordOrderCode)
					.setTime_expire(timeExpire)
					.setAttach("U车查微信小程序")
					.setNotify_url(wxPayV3Bean.getDomain().concat("/ucar/wxPay/rechargeRecordPayNotify"))
					.setAmount(new Amount().setTotal(totalFeel).setCurrency("CNY"))
					.setPayer(new Payer().setOpenid(session.getOpenid()));

			log.info("微信小程序充值支付接口统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
			response = WxPayApi.v3(
					RequestMethodEnum.POST,
					WxDomainEnum.CHINA.toString(),
					BasePayApiEnum.JS_API_PAY.toString(),
					wxPayV3Bean.getMchId(),
					getSerialNumber(),
					null,
					wxPayV3Bean.getKeyPath(),
					JSONUtil.toJsonStr(unifiedOrderModel)
			);
			log.info("微信小程序充值支付接口统一下单响应 {}", response);
			if(StringUtils.isNotNull(response)&&response.getStatus() != OK){
				Map<String, String> map =new HashMap<>();
				map.put("body",	response.getBody());
				map.put("status",new Integer(response.getStatus()).toString());
				commonVoResp.setCode(ResultEnum.WXPAYAPIERROR.getCode());
				commonVoResp.setMessage(ResultEnum.WXPAYAPIERROR.getMsg());
				commonVoResp.setData(map);
				log.info("微信小程序充值支付接口出参:{}",commonVoResp);
				return commonVoResp;
			}
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("微信小程序充值支付接口verifySignature: {}", verifySignature);
			if (response.getStatus() == OK && verifySignature) {
//				TCustomer tCustomer=tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>().eq(TCustomer::getCustomerPhone,rechargeRecordApiPayVoReq.getCustomerPhone()).eq(TCustomer::getDeleteFlag,1l));
				TCustomer tCustomer= tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>()
						.eq(TCustomer::getSysUserId, SecurityUtils.getLoginUser()
								.getUserId()).eq(TCustomer::getDeleteFlag,1L));
				TRechargeRecord tRechargeRecord=new TRechargeRecord();
				tRechargeRecord.setCustomerUuid(tCustomer.getCustomerUuid());
				tRechargeRecord.setRechargeRecordOrderCode(rechargeRecordOrderCode);
				tRechargeRecord.setRechargeMoney(rechargeRecordApiPayVoReq.getTotalFeel());
				tRechargeRecord.setRechargeStatus("noToAccount");
				tRechargeRecord.setRechargeDatetime(LocalDateTimeUtil.now());
				tRechargeRecord.setRechargeRecordUuid(CommonUtil.createUuid());
				tRechargeRecord.setDeleteFlag(1l);
				HashMap<String,Object> map2=new HashMap<String,Object>();
				map2.put("deleteFlag",1l);
				map2.put("customerUuid",tCustomer.getCustomerUuid());
				Integer  rechargeRecordCount=tRechargeRecordMapper.judgeCustomerRechargeRecord(map2);
				if(StringUtils.isNull(rechargeRecordCount)||rechargeRecordCount==0){
					tRechargeRecord.setRechargeType("first_pay");
					if(totalFeel>=10000){
					    tRechargeRecord.setGiveMoney(new BigDecimal(10));
//						tCustomer.setGiftMoney(new BigDecimal(10));
//						tCustomer.setRewardFlag(2l);
//						tCustomerMapper.updateById(tCustomer);
					}
				}else{
					tRechargeRecord.setRechargeType("common_pay");
					tRechargeRecord.setGiveMoney(new BigDecimal(0));
				}
				tRechargeRecordMapper.insertTRechargeRecord(tRechargeRecord);
				String body = response.getBody();
				JSONObject jsonObject = JSONUtil.parseObj(body);
				String prepayId = jsonObject.getStr("prepay_id");
				Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), prepayId, wxPayV3Bean.getKeyPath());
				log.info("微信小程序充值支付接口唤起支付参数:{}", map);
				commonVoResp.setData(map);
			}
			return commonVoResp;
		} catch (Exception e) {
			log.error("系统异常", e);
			if(StringUtils.isNull(response)){
				Map<String, String> map =new HashMap<>();
				map.put("body",	"微信支付响应内容为空！异常信息："+e.getLocalizedMessage());
				map.put("status","404");
				commonVoResp.setCode(ResultEnum.WXPAYAPIERROR.getCode());
				commonVoResp.setMessage(ResultEnum.WXPAYAPIERROR.getMsg());
				commonVoResp.setData(map);
				log.info("微信小程序充值支付接口出参:{}",commonVoResp);
				return commonVoResp;
			}else{
				Map<String, String> map =new HashMap<>();
				map.put("body",	e.getLocalizedMessage());
				map.put("status","500");
				commonVoResp.setCode(ResultEnum.WXPAYAPIERROR.getCode());
				commonVoResp.setMessage(ResultEnum.WXPAYAPIERROR.getMsg());
				commonVoResp.setData(map);
				log.info("微信小程序充值支付接口出参:{}",commonVoResp);
				return commonVoResp;
			}
		}
	}



	@RequestMapping("/wapPay")
	@ResponseBody
	public String wapPay() {
		try {
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
				.setAppid(wxPayV3Bean.getAppId())
				.setMchid(wxPayV3Bean.getMchId())
				.setDescription("U车查查询车辆就是好用")
				.setOut_trade_no(PayKit.generateStr())
				.setTime_expire(timeExpire)
				.setAttach("芜湖咖博网络科技")
				.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
				.setAmount(new Amount().setTotal(1))
				.setScene_info(
					new SceneInfo()
						.setPayer_client_ip("").
						setH5_info(new H5Info()
							.setType("Wap")));

			log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.H5_PAY.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(unifiedOrderModel)
			);
			log.info("统一下单响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (response.getStatus() == OK && verifySignature) {
				String body = response.getBody();
				return JSONUtil.toJsonStr(body);
			}
			return JSONUtil.toJsonStr(response);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}



	@RequestMapping("/put")
	@ResponseBody
	public String put() {
		try {
			Map<String, String> params = new HashMap<>();
			params.put("url", "http://124.221.212.85:8283");

			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.PUT,
				WxDomainEnum.CHINA.toString(),
				ComplaintsApiEnum.COMPLAINTS_NOTIFICATION.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(params)
			);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			log.info("响应 {}", response);
			return response.getBody();
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}


	@RequestMapping("/getParams")
	@ResponseBody
	public String payScoreServiceOrder() {
		try {
			Map<String, String> params = new HashMap<>();
			params.put("service_id", "500001");
			params.put("appid", "wxd678efh567hg6787");
			params.put("out_order_no", "1234323JKHDFE1243252");

			IJPayHttpResponse result = WxPayApi.v3(
				RequestMethodEnum.GET,
				WxDomainEnum.CHINA.toString(),
				PayScoreApiEnum.PAY_SCORE_SERVICE_ORDER.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				params
			);
			System.out.println(result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/delete")
	@ResponseBody
	public String v3Delete() {
		// 创建/查询/更新/删除投诉通知回调
		try {
			HashMap<String, String> hashMap = new HashMap<>(12);
			hashMap.put("url", "http://124.221.212.85:8283");
			IJPayHttpResponse result = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				ComplaintsApiEnum.COMPLAINTS_NOTIFICATION.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(hashMap)
			);
			System.out.println(result);

			result = WxPayApi.v3(
				RequestMethodEnum.DELETE,
				WxDomainEnum.CHINA.toString(),
				ComplaintsApiEnum.COMPLAINTS_NOTIFICATION.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				""
			);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
			System.out.println("verifySignature:" + verifySignature);
			// 如果返回的为 204 表示删除成功
			System.out.println(result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/upload")
	@ResponseBody
	public String v3Upload() {
		// v3 接口上传文件
		try {
			String filePath = "/Users/hxx/IdeaProjects/uchecha-backend/images/xsz.jpg";

			File file = FileUtil.newFile(filePath);
			String sha256 = SecureUtil.sha256(file);

			HashMap<Object, Object> map = new HashMap<>();
			map.put("filename", file.getName());
			map.put("sha256", sha256);
			String body = JSONUtil.toJsonStr(map);

			System.out.println(body);

			IJPayHttpResponse result = WxPayApi.v3(
				WxDomainEnum.CHINA.toString(),
				OtherApiEnum.MERCHANT_UPLOAD_MEDIA.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				body,
				file
			);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
			System.out.println("verifySignature:" + verifySignature);
			System.out.println(result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/post")
	@ResponseBody
	public String payGiftActivity() {
		// 支付有礼-终止活动
		try {
			String urlSuffix = String.format(PayGiftActivityApiEnum.PAY_GIFT_ACTIVITY_TERMINATE.toString(), "10028001");
			System.out.println(urlSuffix);
			IJPayHttpResponse result = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				urlSuffix,
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				""
			);
			System.out.println(result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/sensitive")
	@ResponseBody
	public String sensitive() {
		// 带有敏感信息接口
		try {
			String body = "处理请求参数";

			IJPayHttpResponse result = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				Apply4SubApiEnum.APPLY_4_SUB.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				getPlatSerialNumber(),
				wxPayV3Bean.getKeyPath(),
				body
			);
			System.out.println(result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	public static String sm2Encrypt(String plainText, SM2 sm2) {
		byte[] dateBytes = plainText.getBytes();
		// 这里需要手动设置，sm2 对象的默认值与我们期望的不一致
		sm2.setMode(SM2Engine.Mode.C1C2C3);
		sm2.setEncoding(new PlainDSAEncoding());
		// 加密
		byte[] encrypt = sm2.encrypt(dateBytes);
		return HexUtil.encodeHexStr(encrypt);
	}

	public static String sm2Decrypt(String cipherText, SM2 sm2) {
		// 解密
		byte[] decrypt = sm2.decrypt(HexUtil.decodeHex(cipherText));
		return new String(decrypt);
	}

	@RequestMapping("/cipher")
	@ResponseBody
	public String cipher(@RequestParam(required = false) String authType) {
		try {
			String plainText = "IJPay";
			String privateKeyPath = wxPayV3Bean.getKeyPath();
			String publicKeyPath = wxPayV3Bean.getPublicKeyPath();
			if (StrUtil.equals(authType, AuthTypeEnum.SM2.getCode())) {
				String privateKeyByContent = PayKit.getPrivateKeyByContent(PayKit.getCertFileContent(privateKeyPath));
				String publicKeyByContent = PayKit.getPublicKeyByContent(PayKit.getCertFileContent(publicKeyPath));

				PrivateKey privateKey = PayKit.getPrivateKey(privateKeyPath, AuthTypeEnum.SM2.getCode());
				PublicKey publicKey = PayKit.getSmPublicKey(publicKeyByContent);

				// 创建sm2 对象
				SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
				// SM2 sm2 = SmUtil.sm2(privateKeyByContent, publicKeyByContent);
				String encrypt = sm2Encrypt(plainText, sm2);
				log.info("加密: {}", encrypt);
				log.info("解密: {}", sm2Decrypt(encrypt, sm2));
			} else {
				// 敏感信息加密
				X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));
				String encrypt = PayKit.rsaEncryptOAEP(plainText, certificate);
				log.info("明文:{} 加密后密文:{}", plainText, encrypt);
				// 敏感信息解密
				String encryptStr = "";
				PrivateKey privateKey = PayKit.getPrivateKey(wxPayV3Bean.getKeyPath(), AuthTypeEnum.RSA.getCode());
				String decrypt = PayKit.rsaDecryptOAEP(encryptStr, privateKey);
				log.info("解密后明文:{}", decrypt);
			}
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
		return null;
	}

	/**
	 * 申请交易账单
	 *
	 * @param billDate 2020-06-14 当天账单后一天出，不然会出现「账单日期格式不正确」错误
	 * @return 交易账单下载地址
	 */
	@RequestMapping("/tradeBill")
	@ResponseBody
	public String tradeBill(@RequestParam(value = "billDate", required = false) String billDate) {
		try {
			if (StrUtil.isEmpty(billDate)) {
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(new Date());
				calendar.add(Calendar.DATE, -1);
				billDate = DateUtil.format(calendar.getTime(), "YYYY-MM-dd");
			}
			Map<String, String> params = new HashMap<>(12);
			params.put("bill_date", billDate);
			params.put("bill_type", "ALL");
			params.put("tar_type", "GZIP");

			IJPayHttpResponse result = WxPayApi.v3(
				RequestMethodEnum.GET,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.TRADE_BILL.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				params
			);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			log.info("result:{}", result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	/**
	 * 申请资金账单
	 *
	 * @param billDate 2020-06-14 当天账单后一天出，不然会出现「账单日期格式不正确」错误
	 * @return 资金账单下载地址
	 */
	@RequestMapping("/fundFlowBill")
	@ResponseBody
	public String fundFlowBill(@RequestParam(value = "billDate", required = false) String billDate) {
		try {
			if (StrUtil.isEmpty(billDate)) {
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(new Date());
				calendar.add(Calendar.DATE, -1);
				billDate = DateUtil.format(calendar.getTime(), "YYYY-MM-dd");
			}
			Map<String, String> params = new HashMap<>(12);
			params.put("bill_date", billDate);
			params.put("account_type", "BASIC");

			IJPayHttpResponse result = WxPayApi.v3(
				RequestMethodEnum.GET,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.FUND_FLOW_BILL.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				params
			);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(result, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			log.info("result:{}", result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/billDownload")
	@ResponseBody
	public String billDownload(@RequestParam(value = "token") String token,
							   @RequestParam(value = "tarType", required = false) String tarType) {
		try {

			Map<String, String> params = new HashMap<>(12);
			params.put("token", token);
			if (StrUtil.isNotEmpty(tarType)) {
				params.put("tartype", tarType);
			}

			IJPayHttpResponse result = WxPayApi.v3(
				RequestMethodEnum.GET,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.BILL_DOWNLOAD.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				params
			);
			log.info("result:{}", result);
			return JSONUtil.toJsonStr(result);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}

	@RequestMapping("/batchTransfer")
	@ResponseBody
	public String batchTransfer(@RequestParam(value = "openId", required = false, defaultValue = "o-_-itxuXeGW3O1cxJ7FXNmq8Wf8") String openId) {
		try {
			BatchTransferModel batchTransferModel = new BatchTransferModel()
					.setAppid(wxPayV3Bean.getAppId())
					.setOut_batch_no(PayKit.generateStr())
					.setBatch_name("IJPay 测试微信转账到零钱")
					.setBatch_remark("IJPay 测试微信转账到零钱")
					.setTotal_amount(1)
					.setTotal_num(1)
					.setTransfer_detail_list(Collections.singletonList(
							new TransferDetailInput()
									.setOut_detail_no(PayKit.generateStr())
									.setTransfer_amount(1)
									.setTransfer_remark("IJPay 测试微信转账到零钱")
									.setOpenid(openId)));

			log.info("发起商家转账请求参数 {}", JSONUtil.toJsonStr(batchTransferModel));
			IJPayHttpResponse response = WxPayApi.v3(
					RequestMethodEnum.POST,
					WxDomainEnum.CHINA.toString(),
					TransferApiEnum.TRANSFER_BATCHES.toString(),
					wxPayV3Bean.getMchId(),
					getSerialNumber(),
					null,
					wxPayV3Bean.getKeyPath(),
					JSONUtil.toJsonStr(batchTransferModel)
			);
			log.info("发起商家转账响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (response.getStatus() == OK && verifySignature) {
				return response.getBody();
			}
			return JSONUtil.toJsonStr(response);
		} catch (Exception e) {
			log.error("系统异常", e);
			return e.getMessage();
		}
	}
	@ApiModel("提现-确认出参接口")
	@Data
	public  class TransferToUserResponse {

		@ApiModelProperty("商户单号")
		@SerializedName("out_bill_no")
		public String outBillNo;

		@ApiModelProperty("微信转账单号")
		@SerializedName("transfer_bill_no")
		public String transferBillNo;

		@ApiModelProperty("单据创建时间")
		@SerializedName("create_time")
		public String createTime;

		@ApiModelProperty("单据状态")
		@SerializedName("state")
		public TransferBillStatus state;

		@ApiModelProperty("跳转领取页面的package信息")
		@SerializedName("package_info")
		public String packageInfo;

		@ApiModelProperty("商户号")
		public String mchId;

		@ApiModelProperty("商户AppID")
		public String appId;
	}
	@ApiModel("提现-撤销转账出参接口")
	@Data
	public  class CancelTransferToUserResponse {

		@ApiModelProperty("商户单号")
		@SerializedName("out_bill_no")
		public String outBillNo;

		@ApiModelProperty("微信转账单号")
		@SerializedName("transfer_bill_no")
		public String transferBillNo;

		@ApiModelProperty("最后一次单据状态变更时间")
		@SerializedName("update_time")
		public String updateTime;

		@ApiModelProperty("单据状态")
		@SerializedName("state")
		public CancelTransferBillStatus state;

	}
	public enum TransferBillStatus {
		@SerializedName("ACCEPTED")
		ACCEPTED,
		@SerializedName("PROCESSING")
		PROCESSING,
		@SerializedName("WAIT_USER_CONFIRM")
		WAIT_USER_CONFIRM,
		@SerializedName("TRANSFERING")
		TRANSFERING,
		@SerializedName("SUCCESS")
		SUCCESS,
		@SerializedName("FAIL")
		FAIL,
		@SerializedName("CANCELING")
		CANCELING,
		@SerializedName("CANCELLED")
		CANCELLED
	}

	public enum CancelTransferBillStatus {
		@SerializedName("CANCELING")
		CANCELING,
		@SerializedName("CANCELLED")
		CANCELLED

	}



	// step1 生成账单
	public TransferToUserResponse createTransferBills(String orderNo, String openId, String userName, BigDecimal money,TCustomer tCustomer,String withdrawType) throws Exception{
		OkHttpClient okHttpClient = new OkHttpClient();
		HttpClient httpClient = new DefaultHttpClientBuilder()
				.config(rsaAutoCertificateConfig())
				.okHttpClient(okHttpClient)
				.build();
		HttpHeaders headers = new HttpHeaders();
		headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue());
		headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue());
		headers.addHeader("Wechatpay-Serial", wxPayV3Bean.getMchSerialNo()); // 商户证书序列号
		long totalFeel=(money.multiply(new BigDecimal("100"))).longValue();

		HashMap<Object, Object> map = new HashMap<>();
		map.put("appid", wxPayV3Bean.getAppId()); //小程序 appId
		map.put("out_bill_no", orderNo); // 订单编号
		map.put("transfer_scene_id", "1000"); // 转账场景ID
		map.put("openid", openId);  // openid
		// 收款用户姓名（需要加密传入）
//		if (StringUtils.isNotEmpty(userName)&&totalFeel>30) {
//			map.put("user_name", rsaEncryptOAEP(userName));
//		}
		log.info("提现用户信息： {}", tCustomer);

		map.put("transfer_amount", totalFeel);  //金额(分)
		map.put("transfer_remark", "提现结算: u车查"); // 转账备注
		map.put("notify_url", wxPayV3Bean.getDomain().concat("/ucar/wxPay/withdrawNotify"));  //回调地址: 商家转账回调地址
		map.put("user_recv_perception", "现金奖励");  // 用户收款感知
		// 转账场景报备信息
		JSONArray jsonArray = new JSONArray();
		jsonArray.add(new JSONObject().set("info_type", "活动名称").set("info_content", "货款回收"));
		jsonArray.add(new  JSONObject().set("info_type", "奖励说明").set("info_content", "货款回收结算"));
		map.put("transfer_scene_report_infos", jsonArray);

		JsonRequestBody build = new JsonRequestBody.Builder()
				.body(JSONUtil.toJsonStr(map))
				.build();
		HttpRequest executeSendGetHttpRequest = new HttpRequest.Builder()
				.httpMethod(HttpMethod.POST)
				.url("https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills")
				.headers(headers)
				.body(build)
				.build();
		    log.info("发起商家转账请求 {}", executeSendGetHttpRequest);
			HttpResponse<TransferToUserResponse> execute = httpClient.execute(executeSendGetHttpRequest, TransferToUserResponse.class);
			log.info("微信支付-提现接口返回JSON数据 {}", execute);
			TransferToUserResponse transferToUserResponse=execute.getServiceResponse();
            if(transferToUserResponse.getState().equals(TransferBillStatus.WAIT_USER_CONFIRM)) {
				TWithdrawRecord tWithdrawRecord = new TWithdrawRecord();
				tWithdrawRecord.setCustomerUuid(tCustomer.getCustomerUuid());
				tWithdrawRecord.setDeleteFlag(1l);
				tWithdrawRecord.setWithdrawMoney(money);
				tWithdrawRecord.setWithdrawDatetime(LocalDateTimeUtil.now());
			 	tWithdrawRecord.setWithdrawWay("wechat_withdraw");
				tWithdrawRecord.setWithdrawRecordUuid(CommonUtil.createUuid());
				tWithdrawRecord.setWithdrawType(withdrawType);
				tWithdrawRecord.setWithdrawStatus("noToAccount");
				tWithdrawRecord.setOrderNo(orderNo);
				if("withdraw1".equals(withdrawType) ) {
					tWithdrawRecord.setOldBalance(tCustomer.getBalanceNumber());
					tWithdrawRecord.setNowBalance(tCustomer.getBalanceNumber().subtract(money));
					tCustomer.setBalanceNumber(tCustomer.getBalanceNumber().subtract(money));
				}
				if("withdraw2".equals(withdrawType) ) {
					tWithdrawRecord.setOldBalance(tCustomer.getTotalAgencyFee());
 					tWithdrawRecord.setNowBalance(tCustomer.getTotalAgencyFee().subtract(money));
					tCustomer.setTotalAgencyFee(tCustomer.getTotalAgencyFee().subtract(money));
				}
				tCustomerMapper.updateById(tCustomer);
				itWithdrawRecordService.saveOrUpdate(tWithdrawRecord);
			}
		    transferToUserResponse.setMchId(wxPayV3Bean.getMchId());
		    transferToUserResponse.setAppId(wxPayV3Bean.getAppId());
		    return transferToUserResponse;
	}

	// API安全加密配置
	private RSAAutoCertificateConfig rsaAutoCertificateConfig() {
		return new RSAAutoCertificateConfig.Builder()
				.merchantId(wxPayV3Bean.getMchId())  // 商户号
				.privateKeyFromPath(wxPayV3Bean.getKeyPath())  // 商户API证书私钥的存放路径
				.merchantSerialNumber(wxPayV3Bean.getMchSerialNo())  // 商户API证书序列号
				.apiV3Key(wxPayV3Bean.getApiKey3())  // APIv3密钥
				.build();
	}

	// 敏感信息加密
	private String rsaEncryptOAEP(String message) throws Exception{
		    X509Certificate cert = getX509Certificate();
			Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
			cipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
			byte[] data = message.getBytes(StandardCharsets.UTF_8);
			byte[] cipherdata = cipher.doFinal(data);
			return Base64.getEncoder().encodeToString(cipherdata);
	}

	// 获取 X509Certificate
	private X509Certificate getX509Certificate() throws Exception {
 	     	InputStream in = new FileInputStream(wxPayV3Bean.getPlatformCertPath());
 			if (in == null) {
				throw new IOException("Resource not found: " + wxPayV3Bean.getPlatformCertPath());
			}
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			return (X509Certificate) cf.generateCertificate(in);
	}




	@PostMapping(value = "/withdrawNotify" )
	@ResponseBody
	@Anonymous
	public UCarOrderRefundNotifyVoResp withdrawNotify(HttpServletRequest request) {
		UCarOrderRefundNotifyVoResp uCarOrderRefundNotifyVoResp=new UCarOrderRefundNotifyVoResp();
		try {
			String timestamp = request.getHeader("Wechatpay-Timestamp");
			String nonce = request.getHeader("Wechatpay-Nonce");
			String serialNo = request.getHeader("Wechatpay-Serial");
			String signature = request.getHeader("Wechatpay-Signature");
			log.info("提现回调通知 timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
			String result = HttpKit.readData(request);
			log.info("提现回调通知密文 {}", result);
//			String plainText = null;
			// 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
			String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
					wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
			// 微信公钥验证签名并解密
//			if (StringUtils.equals(serialNo, wxPayV3Bean.getPublicKeyId())) {
//				plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
//					wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
//			}
			log.info("提现回调通知明文 {}", plainText);

			if (StrUtil.isNotEmpty(plainText)) {
				// 3. 解密业务数据
				JSONObject json = JSONUtil.parseObj(plainText);
				String outTradeNo = json
						.getStr("out_bill_no");
				String state = json
						.getStr("state");
				TWithdrawRecord tWithdrawRecord=itWithdrawRecordService.getOne(new LambdaQueryWrapper<TWithdrawRecord>().eq(TWithdrawRecord::getOrderNo,outTradeNo).eq(TWithdrawRecord::getDeleteFlag,1l));
				if(StringUtils.isNotEmpty(state)&&"SUCCESS".equals(state)) {
					    tWithdrawRecord.setWithdrawStatus("toAccount");

					    TCustomer tCustomer= tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>()
								.eq(TCustomer::getCustomerUuid, tWithdrawRecord.getCustomerUuid()).eq(TCustomer::getDeleteFlag,1L));
					    BigDecimal zero=new BigDecimal(0.000000);
						if(tCustomer.getGiftMoney().compareTo(zero)>0) {
							TConsumeData tConsumeData=new TConsumeData();
							tConsumeData.setCustomerUuid(tCustomer.getCustomerUuid());
							tConsumeData.setDeleteFlag(1l);
							tConsumeData.setConsumeMoney(tCustomer.getGiftMoney());
							tConsumeData.setBalanceMoney(tCustomer.getGiftMoney().add(tCustomer.getBalanceNumber()).add(tCustomer.getReturnMoney()).add(tCustomer.getTotalAgencyFee()));
							tConsumeData.setConsumeType("backGitMoney");
							itConsumeDataService.save(tConsumeData);
							tCustomer.setGiftMoney(zero);
							tCustomerMapper.updateById(tCustomer);
						}
				}
				if(StringUtils.isNotEmpty(state)&&"CANCELLED".equals(state)) {
					tWithdrawRecord.setWithdrawStatus("toAccountCancel");
					TCustomer tCustomer= tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>()
							.eq(TCustomer::getCustomerUuid, tWithdrawRecord.getCustomerUuid()).eq(TCustomer::getDeleteFlag,1L));
					if(StringUtils.isNotNull(tCustomer)&&"withdraw1".equals(tWithdrawRecord.getWithdrawType())&&"wechat_withdraw".equals(tWithdrawRecord.getWithdrawWay())){
						tCustomer.setBalanceNumber(tCustomer.getBalanceNumber().add(tWithdrawRecord.getWithdrawMoney()));
						tCustomerMapper.updateById(tCustomer);
					}
					if(StringUtils.isNotNull(tCustomer)&&"agentCus".equals(tCustomer.getCustomerType())&&"withdraw2".equals(tWithdrawRecord.getWithdrawType())&&"wechat_withdraw".equals(tWithdrawRecord.getWithdrawWay())){
						tCustomer.setTotalAgencyFee(tCustomer.getTotalAgencyFee().add(tWithdrawRecord.getWithdrawMoney()));
						tCustomerMapper.updateById(tCustomer);
					}
				}
				if(StringUtils.isNotEmpty(state)&&"FAIL".equals(state)) {
					tWithdrawRecord.setWithdrawStatus("toAccountFail");
					TCustomer tCustomer= tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>()
							.eq(TCustomer::getCustomerUuid, tWithdrawRecord.getCustomerUuid()).eq(TCustomer::getDeleteFlag,1L));
					if(StringUtils.isNotNull(tCustomer)&&"withdraw1".equals(tWithdrawRecord.getWithdrawType())&&"wechat_withdraw".equals(tWithdrawRecord.getWithdrawWay())){
						tCustomer.setBalanceNumber(tCustomer.getBalanceNumber().add(tWithdrawRecord.getWithdrawMoney()));
						tCustomerMapper.updateById(tCustomer);
					}
					if(StringUtils.isNotNull(tCustomer)&&"agentCus".equals(tCustomer.getCustomerType())&&"withdraw2".equals(tWithdrawRecord.getWithdrawType())&&"wechat_withdraw".equals(tWithdrawRecord.getWithdrawWay())){
						tCustomer.setTotalAgencyFee(tCustomer.getTotalAgencyFee().add(tWithdrawRecord.getWithdrawMoney()));
						tCustomerMapper.updateById(tCustomer);
					}
				}
				itWithdrawRecordService.updateById(tWithdrawRecord);
				//提现成功大于100 赠送金额还原
//				List<TWithdrawRecord> tWithdrawRecordList=itWithdrawRecordService.list(new LambdaQueryWrapper<TWithdrawRecord>().eq(TWithdrawRecord::getCustomerUuid,tWithdrawRecord.getCustomerUuid()).eq(TWithdrawRecord::getDeleteFlag,1l).eq(TWithdrawRecord::getWithdrawStatus,"toAccount").eq(TWithdrawRecord::getWithdrawType,"withdraw1").eq(TWithdrawRecord::getWithdrawWay,"wechat_withdraw"));
//                if(StringUtils.isNotNull(tWithdrawRecordList)&&tWithdrawRecordList.size()>0){
//					 BigDecimal totolWithDraw=new BigDecimal(0.000000);
//
//					for (TWithdrawRecord tWithdrawRecord1:
//					tWithdrawRecordList) {
//						totolWithDraw=totolWithDraw.add(tWithdrawRecord1.getWithdrawMoney());
//					}
//					if(totolWithDraw.compareTo(new BigDecimal(100.000000))>=0){
//						TCustomer tCustomer= tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>()
//								.eq(TCustomer::getCustomerUuid, tWithdrawRecord.getCustomerUuid()).eq(TCustomer::getDeleteFlag,1L));
//						tCustomer.setGiftMoney(new BigDecimal(0.000000));
//						tCustomerMapper.updateById(tCustomer);
//					}
//
//				}
			} else {
				uCarOrderRefundNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
				uCarOrderRefundNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			}
			log.info("提现回调通知成功后回调接口出参：{}", uCarOrderRefundNotifyVoResp);
			return uCarOrderRefundNotifyVoResp;
		}  catch (Exception e) {
			log.error("系统异常", e);
			uCarOrderRefundNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
			uCarOrderRefundNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			log.info("提现回调通知成功后回调接口出参：{}", uCarOrderRefundNotifyVoResp);
			return uCarOrderRefundNotifyVoResp;
		}

	}

	// 撤销账单
	public CancelTransferToUserResponse cancelTransferBills(String outBillNo) throws Exception{
		OkHttpClient okHttpClient = new OkHttpClient();
		HttpClient httpClient = new DefaultHttpClientBuilder()
				.config(rsaAutoCertificateConfig())
				.okHttpClient(okHttpClient)
				.build();
		HttpHeaders headers = new HttpHeaders();
		headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue());
		headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue());
		headers.addHeader("Wechatpay-Serial", wxPayV3Bean.getMchSerialNo()); // 商户证书序列号
		JsonRequestBody build = new JsonRequestBody.Builder()
				.body("")
				.build();
		HttpRequest executeSendGetHttpRequest = new HttpRequest.Builder()
				.httpMethod(HttpMethod.POST)
				.url("https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/"+outBillNo+"/cancel")
				.headers(headers)
				.body(build)
				.build();
		log.info("发起撤销转账请求 {}", executeSendGetHttpRequest);
		HttpResponse<CancelTransferToUserResponse> execute = httpClient.execute(executeSendGetHttpRequest, CancelTransferToUserResponse.class);
		log.info("微信支付-提现撤销转账接口返回JSON数据 {}", execute);
		CancelTransferToUserResponse cancelTransferToUserResponse=execute.getServiceResponse();
		return cancelTransferToUserResponse;
	}

	@PostMapping("/cancelWithdraw")
	@ResponseBody
	@ApiOperation("微信支付-撤销转账接口")
	@Anonymous
	public CommonVoResp<CancelTransferToUserResponse> cancelTransfer(@RequestBody CancelWithdrawApiPayVoReq cancelWithdrawApiPayVoReq) {
		log.info("微信支付-撤销转账接口入参 {}", cancelWithdrawApiPayVoReq);
		CommonVoResp<CancelTransferToUserResponse> commonVoResp=new CommonVoResp<>();
		if(
				cancelWithdrawApiPayVoReq.getOutBillNo()==null){
			return CommonUtil.setCommonVoRespNoParam(commonVoResp);
		}

		try {
			CancelTransferToUserResponse cancelTransferToUserResponse=cancelTransferBills(cancelWithdrawApiPayVoReq.getOutBillNo());
			commonVoResp.setData(cancelTransferToUserResponse);
			log.info("微信支付-撤销转账接口出参数据 {}", commonVoResp);
			return commonVoResp;
		} catch (ServiceException e) {
			log.error("微信支付-撤销转账接口系统异常", e);
			commonVoResp.setCode(ResultEnum.WXPAYWITHDRAWERROR.getCode());
			commonVoResp.setMessage(JSONUtil.parseObj(e.getResponseBody()).getStr("message")  );
			log.info("微信支付-撤销转账接口出参：{}", commonVoResp);
			return commonVoResp;
		}catch (Exception e) {
			log.error("微信支付-撤销转账接口系统异常", e);
			commonVoResp.setCode(ResultEnum.WXPAYWITHDRAWERROR.getCode());
			commonVoResp.setMessage(e.getMessage());
			log.info("微信支付-撤销转账接口出参：{}", commonVoResp);
			return commonVoResp;
		}
	}


	@PostMapping("/withdraw")
	@ResponseBody
	@ApiOperation("微信支付-提现接口")
	public CommonVoResp<TransferToUserResponse> batchTransfer(@RequestBody WithdrawApiPayVoReq withdrawApiPayVoReq) {
		log.info("微信支付-提现接口入参 {}", withdrawApiPayVoReq);
		CommonVoResp<TransferToUserResponse> commonVoResp=new CommonVoResp<>();
		if(
				withdrawApiPayVoReq.getTotalFeel()==null||
						withdrawApiPayVoReq.getCode()==null){
			return CommonUtil.setCommonVoRespNoParam(commonVoResp);
		}
		TCustomer tCustomer= tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>()
				.eq(TCustomer::getSysUserId, SecurityUtils.getLoginUser()
						.getUserId()).eq(TCustomer::getDeleteFlag,1L));

		if("withdraw1".equals(withdrawApiPayVoReq.getWithdrawType())&&withdrawApiPayVoReq.getTotalFeel().compareTo(tCustomer.getBalanceNumber())>0){
			commonVoResp.setCode(ResultEnum.WXPAYWITHDRAW.getCode());
			commonVoResp.setMessage(ResultEnum.WXPAYWITHDRAW.getMsg());
			log.info("微信支付-提现接口出参：{}", commonVoResp);
			return  commonVoResp;
		}
		if("withdraw2".equals(withdrawApiPayVoReq.getWithdrawType())&&withdrawApiPayVoReq.getTotalFeel().compareTo(tCustomer.getTotalAgencyFee())>0){
			commonVoResp.setCode(ResultEnum.WXPAYWITHDRAWANGET.getCode());
			commonVoResp.setMessage(ResultEnum.WXPAYWITHDRAWANGET.getMsg());
			log.info("微信支付-提现接口出参：{}", commonVoResp);
			return  commonVoResp;
		}
		try {
			// 1. 获取session_key和openid
			WxMaJscode2SessionResult session = wxMaService.getUserService()
					.getSessionInfo(withdrawApiPayVoReq.getCode());
			log.info("微信一键登录返回session对象：{}",session.toString() );
			String openId=session.getOpenid();
			TransferToUserResponse transferToUserResponse=createTransferBills(PayKit.generateStr(),openId,tCustomer.getRealName(),withdrawApiPayVoReq.getTotalFeel(),tCustomer,withdrawApiPayVoReq.getWithdrawType());
			commonVoResp.setData(transferToUserResponse);
			log.info("微信支付-提现接口出参数据 {}", commonVoResp);
			return commonVoResp;
		} catch (ServiceException e) {
			log.error("微信支付-提现系统异常", e);
			commonVoResp.setCode(ResultEnum.WXPAYWITHDRAWERROR.getCode());
			commonVoResp.setMessage(JSONUtil.parseObj(e.getResponseBody()).getStr("message")  );
			log.info("微信支付-提现接口出参：{}", commonVoResp);
			return commonVoResp;
		}catch (Exception e) {
			log.error("微信支付-撤销转账接口系统异常", e);
			commonVoResp.setCode(ResultEnum.WXPAYWITHDRAWERROR.getCode());
			commonVoResp.setMessage(ResultEnum.WXPAYWITHDRAWERROR.getMsg());
			log.info("微信支付-提现接口出参：{}", commonVoResp);
			return commonVoResp;
		}
	}

	@PostMapping("/old-withdraw")
	public CommonVoResp<String> withdraw(@RequestBody WithdrawApiPayVoReq withdrawApiPayVoReq) {
		log.info("微信支付-提现接口入参 {}", withdrawApiPayVoReq);
		CommonVoResp<String> commonVoResp=new CommonVoResp<>();
		if(
				withdrawApiPayVoReq.getTotalFeel()==null||
						withdrawApiPayVoReq.getCode()==null){
			return CommonUtil.setCommonVoRespNoParam(commonVoResp);
		}
		TCustomer tCustomer= tCustomerMapper.selectOne(new LambdaQueryWrapper<TCustomer>()
				.eq(TCustomer::getSysUserId, SecurityUtils.getLoginUser()
						.getUserId()).eq(TCustomer::getDeleteFlag,1L));
		BigDecimal totlBalance= tCustomer.getTotalAgencyFee().add(tCustomer.getBalanceNumber());
        if(withdrawApiPayVoReq.getTotalFeel().compareTo(totlBalance)>0){
			commonVoResp.setCode(ResultEnum.WXPAYWITHDRAW.getCode());
			commonVoResp.setMessage(ResultEnum.WXPAYWITHDRAW.getMsg());
			log.info("微信支付-提现接口出参：{}", commonVoResp);
			return  commonVoResp;
		}
		try {
			// 1. 获取session_key和openid
			WxMaJscode2SessionResult session = wxMaService.getUserService()
					.getSessionInfo(withdrawApiPayVoReq.getCode());
			log.info("微信一键登录返回session对象：{}",session.toString() );
			String openId=session.getOpenid();
			int totalFeel=(withdrawApiPayVoReq.getTotalFeel().multiply(new BigDecimal("100"))).intValue();
			BatchTransferModel batchTransferModel = new BatchTransferModel()
					.setAppid(wxPayV3Bean.getAppId())
					.setOut_batch_no(PayKit.generateStr())
					.setBatch_name("U车查微信转账到零钱")
					.setBatch_remark("U车查微信转账到零钱")
					.setTotal_amount(totalFeel)
					.setTotal_num(1)
					.setTransfer_detail_list(Collections.singletonList(
							new TransferDetailInput()
									.setOut_detail_no(PayKit.generateStr())
									.setTransfer_amount(totalFeel)
									.setTransfer_remark("U车查微信转账到零钱")
									.setOpenid(openId)));

			log.info("发起商家转账请求参数 {}", JSONUtil.toJsonStr(batchTransferModel));
			IJPayHttpResponse response = WxPayApi.v3(
					RequestMethodEnum.POST,
					WxDomainEnum.CHINA.toString(),
					TransferApiEnum.TRANSFER_BATCHES.toString(),
					wxPayV3Bean.getMchId(),
					getSerialNumber(),
					null,
					wxPayV3Bean.getKeyPath(),
					JSONUtil.toJsonStr(batchTransferModel)
			);
			log.info("发起商家转账响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (response.getStatus() == OK && verifySignature) {
				BigDecimal zeroBigDecimal=  new BigDecimal(0);
				if(tCustomer.getBalanceNumber().compareTo(withdrawApiPayVoReq.getTotalFeel())>=0){
					tCustomer.setBalanceNumber(tCustomer.getBalanceNumber().subtract(withdrawApiPayVoReq.getTotalFeel()));
				}else{
					BigDecimal unpaidAmount=withdrawApiPayVoReq.getTotalFeel().subtract(tCustomer.getBalanceNumber());
					tCustomer.setBalanceNumber(zeroBigDecimal);
					tCustomer.setTotalAgencyFee(tCustomer.getTotalAgencyFee().subtract(unpaidAmount));
				}
				tCustomerMapper.updateById(tCustomer);
				TWithdrawRecord tWithdrawRecord=new TWithdrawRecord();
				tWithdrawRecord.setCustomerUuid(tCustomer.getCustomerUuid());
				tWithdrawRecord.setDeleteFlag(1l);
				tWithdrawRecord.setWithdrawMoney(withdrawApiPayVoReq.getTotalFeel());
				tWithdrawRecord.setWithdrawDatetime(LocalDateTimeUtil.now());
				tWithdrawRecord.setOldBalance(totlBalance);
				tWithdrawRecord.setNowBalance(totlBalance.subtract(withdrawApiPayVoReq.getTotalFeel()));
				tWithdrawRecord.setWithdrawWay("wechat_withdraw");
				tWithdrawRecord.setWithdrawRecordUuid(CommonUtil.createUuid());
				itWithdrawRecordService.saveOrUpdate(tWithdrawRecord);
				commonVoResp.setData(response.getBody());
				log.info("微信支付-提现接口出参：{}", commonVoResp);
				return  commonVoResp;
			}else{
				commonVoResp.setCode(ResultEnum.WXPAYWITHDRAW.getCode());
				commonVoResp.setMessage(JSONUtil.parseObj(response.getBody()).get("message").toString());
				log.info("微信支付-提现接口出参：{}", commonVoResp);
				return  commonVoResp;
			}

		} catch (Exception e) {
			log.error("系统异常", e);
			commonVoResp.setCode(ResultEnum.WXPAYREFUND.getCode());
			commonVoResp.setMessage(e.getMessage());
			log.info("微信支付-提现接口出参：{}", commonVoResp);
			return commonVoResp;
		}
	}


	@PostMapping("/refund")
	@ResponseBody
	@ApiOperation("微信支付-退款接口")
	public CommonVoResp<String> refund(@RequestBody UCarOrderRefundVoReq uCarOrderRefundVoReq) {

		log.info("微信支付-退款接口入参 {}", uCarOrderRefundVoReq);
		CommonVoResp<String> commonVoResp=new CommonVoResp<>();
		try {
			String outRefundNo = PayKit.generateStr();
			log.info("商户退款单号: {}", outRefundNo);
			int totalFeel=(uCarOrderRefundVoReq.getTotalFeel().multiply(new BigDecimal("100"))).intValue();

//			List<RefundGoodsDetail> list = new ArrayList<>();
//			RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
//				.setMerchant_goods_id("123")
//				.setGoods_name("U车查产品退款")
//				.setUnit_price(1)
//				.setRefund_amount(totalFeel)
//				.setRefund_quantity(1);
//			list.add(refundGoodsDetail);
			String  transactionId=uCarOrderRefundVoReq.getTransactionId();
			String  orderCode=uCarOrderRefundVoReq.getOrderCode();

			RefundModel refundModel = new RefundModel()
				.setOut_refund_no(outRefundNo)
				.setReason("U车查产品退款")
				.setNotify_url(wxPayV3Bean.getDomain().concat("/ucar/wxPay/refundNotify"))
				.setAmount(new RefundAmount().setRefund(totalFeel).setTotal(totalFeel).setCurrency("CNY"));
//				.setGoods_detail(list);

			if (StrUtil.isNotEmpty(transactionId)) {
				refundModel.setTransaction_id(transactionId);
			}
			if (StrUtil.isNotEmpty(orderCode)) {
				refundModel.setOut_trade_no(orderCode);
			}
			log.info("退款参数 {}", JSONUtil.toJsonStr(refundModel));
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.REFUND.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(refundModel)
			);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			// 微信支付公钥验证签名
//			boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			log.info("退款响应 {}", response);
			if(response.getStatus()!=200){
				commonVoResp.setCode(ResultEnum.WXPAYREFUND.getCode());
				commonVoResp.setMessage(JSONUtil.parseObj(response.getBody()).get("message").toString());
				log.info("微信支付-退款接口出参：{}", commonVoResp);
				return  commonVoResp;
			}
			if (verifySignature&&response.getStatus()==OK) {
				UcarOrderUpdateStatusBoReq ucarOrderUpdateStatusBoReq=new UcarOrderUpdateStatusBoReq();
				ucarOrderUpdateStatusBoReq.setOrderStatus("waitCancel");
				ucarOrderUpdateStatusBoReq.setOrderCode(orderCode);
				ucarOrderUpdateStatusBoReq.setChargeDatetime(LocalDateTimeUtil.now());
				itOrderService.updateOrderStatus(ucarOrderUpdateStatusBoReq,null);
				commonVoResp.setData(response.getBody());
				log.info("微信支付-退款接口出参：{}", commonVoResp);
				return  commonVoResp;
			}
		} catch (Exception e) {
			log.error("系统异常", e);
			commonVoResp.setCode(ResultEnum.WXPAYREFUND.getCode());
			commonVoResp.setMessage(e.getMessage());
			log.info("微信支付-退款接口出参：{}", commonVoResp);
			return  commonVoResp;
		}
		return null;
	}



	@PostMapping(value = "/payNotify")
	@ResponseBody
	@Anonymous
	public UCarOrderPayNotifyVoResp payNotify(HttpServletRequest request) {
		UCarOrderPayNotifyVoResp  uCarOrderPayNotifyVoResp=new UCarOrderPayNotifyVoResp();
		Map<String, String> map = new HashMap<>(12);
		try {
			String timestamp = request.getHeader("Wechatpay-Timestamp");
			String nonce = request.getHeader("Wechatpay-Nonce");
			String serialNo = request.getHeader("Wechatpay-Serial");
			String signature = request.getHeader("Wechatpay-Signature");

			log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
			String result = HttpKit.readData(request);
			log.info("支付通知密文 {}", result);
//			String plainText = null;
			// 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
			String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
				wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
			// 微信公钥验证签名并解密
//			if (StringUtils.equals(serialNo, wxPayV3Bean.getPublicKeyId())) {
//				plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
//					wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
//			}
			log.info("支付通知明文 {}", plainText);

			if (StrUtil.isNotEmpty(plainText)) {
				// 3. 解密业务数据
				JSONObject json = JSONUtil.parseObj(plainText);
				String outTradeNo = json
						.getStr("out_trade_no");
				String transactionId = json
						.getStr("transaction_id");
				// 4. 处理订单逻辑
				UcarOrderUpdateStatusBoReq ucarOrderUpdateStatusBoReq=new UcarOrderUpdateStatusBoReq();
				ucarOrderUpdateStatusBoReq.setPayStatus("paid");
				ucarOrderUpdateStatusBoReq.setOrderStatus("waitVaild");
				ucarOrderUpdateStatusBoReq.setOrderCode(outTradeNo);
				ucarOrderUpdateStatusBoReq.setPayDatetime(LocalDateTimeUtil.now());
				ucarOrderUpdateStatusBoReq.setTransactionId(transactionId);
				itOrderService.updateOrderStatus(ucarOrderUpdateStatusBoReq,null);
				//5.更新微信支付中的订单号
//				UcarOrderUpdateTransactionIdBoReq ucarOrderUpdateTransactionIdBoReq=new UcarOrderUpdateTransactionIdBoReq();
//				ucarOrderUpdateTransactionIdBoReq.setOrderCode(outTradeNo);
//				ucarOrderUpdateTransactionIdBoReq.setTransactionId(transactionId);
//				itOrderService.updateOrderTransactionId(ucarOrderUpdateTransactionIdBoReq);
				BigDecimal zeroBigDecimal=  new BigDecimal(0);
				//扣除余额和赠送金额操作
				TOrderPayDetail tOrderPayDetail=itOrderPayDetailService.getBaseMapper().selectOne(new LambdaQueryWrapper<TOrderPayDetail>().eq(TOrderPayDetail::getOrderCode,outTradeNo).eq(TOrderPayDetail::getDeleteFlag,1l));
				if(StringUtils.isNotNull(tOrderPayDetail)){
					 if(tOrderPayDetail.getGiftMoneyPay().compareTo(zeroBigDecimal)>0||tOrderPayDetail.getBalancePay().compareTo(zeroBigDecimal)>0||tOrderPayDetail.getReturnMoneyPay().compareTo(zeroBigDecimal)>0){
						 HashMap<String,Object> map2=new HashMap<>();
						 map2.put("orderCode",outTradeNo);
						 map2.put("deleteFlag",1l);
						 TCustomer tCustomer= tCustomerMapper.selectCustomerByOrderCode(map2);
						 tCustomer.setBalanceNumber(tCustomer.getBalanceNumber().subtract(tOrderPayDetail.getBalancePay()));
						 tCustomer.setGiftMoney(tCustomer.getGiftMoney().subtract(tOrderPayDetail.getGiftMoneyPay()));
						 tCustomer.setReturnMoney(tCustomer.getReturnMoney().subtract(tOrderPayDetail.getReturnMoneyPay()));
						 tCustomerMapper.updateById(tCustomer);
					 }
				}
			} else {
				uCarOrderPayNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
				uCarOrderPayNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			}
			log.info("支付成功后回调接口出参：{}", uCarOrderPayNotifyVoResp);
			return uCarOrderPayNotifyVoResp;
		} catch (Exception e) {
			log.error("支付成功后回调接口系统异常", e);
			uCarOrderPayNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
			uCarOrderPayNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			log.info("支付成功后回调接口出参：{}", uCarOrderPayNotifyVoResp);
			return uCarOrderPayNotifyVoResp;
		}
	}

	@PostMapping(value = "/refundNotify" )
	@ResponseBody
	@Anonymous
	public UCarOrderRefundNotifyVoResp refundNotify(HttpServletRequest request) {
		UCarOrderRefundNotifyVoResp uCarOrderRefundNotifyVoResp=new UCarOrderRefundNotifyVoResp();
		try {
			String timestamp = request.getHeader("Wechatpay-Timestamp");
			String nonce = request.getHeader("Wechatpay-Nonce");
			String serialNo = request.getHeader("Wechatpay-Serial");
			String signature = request.getHeader("Wechatpay-Signature");
			log.info("退款通知 timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
			String result = HttpKit.readData(request);
			log.info("退款通知密文 {}", result);
//			String plainText = null;
			// 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
			String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
				wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
			// 微信公钥验证签名并解密
//			if (StringUtils.equals(serialNo, wxPayV3Bean.getPublicKeyId())) {
//				plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
//					wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
//			}
			log.info("退款通知明文 {}", plainText);

			if (StrUtil.isNotEmpty(plainText)) {
				// 3. 解密业务数据
				JSONObject json = JSONUtil.parseObj(plainText);
				String outTradeNo = json
						.getStr("out_trade_no");
				String transactionId = json
						.getStr("transaction_id");
				// 4. 处理订单逻辑
				UcarOrderUpdateStatusBoReq ucarOrderUpdateStatusBoReq=new UcarOrderUpdateStatusBoReq();
				ucarOrderUpdateStatusBoReq.setPayStatus("payInvalid");
				ucarOrderUpdateStatusBoReq.setOrderStatus("invalid");
				ucarOrderUpdateStatusBoReq.setOrderCode(outTradeNo);
				TCustomer tCustomer=null;

						//还原余额和赠送金额操作
				BigDecimal zeroBigDecimal=  new BigDecimal(0);
				TOrderPayDetail tOrderPayDetail=itOrderPayDetailService.getBaseMapper().selectOne(new LambdaQueryWrapper<TOrderPayDetail>().eq(TOrderPayDetail::getOrderCode,outTradeNo).eq(TOrderPayDetail::getDeleteFlag,1l));
				if(StringUtils.isNotNull(tOrderPayDetail)){
					HashMap<String,Object> map2=new HashMap<>();
					map2.put("orderCode",outTradeNo);
					map2.put("deleteFlag",1l);
					  tCustomer= tCustomerMapper.selectCustomerByOrderCode(map2);
					if(tOrderPayDetail.getGiftMoneyPay().compareTo(zeroBigDecimal)>0){
						tCustomer.setGiftMoney(tCustomer.getGiftMoney().subtract(tOrderPayDetail.getGiftMoneyPay()));
					}
					if(tOrderPayDetail.getBalancePay().compareTo(zeroBigDecimal)>0){
						tCustomer.setBalanceNumber(tCustomer.getBalanceNumber().add(tOrderPayDetail.getBalancePay()));
					}
					if(tOrderPayDetail.getReturnMoneyPay().compareTo(zeroBigDecimal)>0){
						tCustomer.setReturnMoney(tCustomer.getReturnMoney().add(tOrderPayDetail.getReturnMoneyPay()));
					}
				}
				itOrderService.updateOrderStatus(ucarOrderUpdateStatusBoReq,tCustomer);
			} else {
				uCarOrderRefundNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
				uCarOrderRefundNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			}
			log.info("退款成功后回调接口出参：{}", uCarOrderRefundNotifyVoResp);
			return uCarOrderRefundNotifyVoResp;
		} catch (Exception e) {
			log.error("系统异常", e);
			uCarOrderRefundNotifyVoResp.setCode(ResultEnum.FAIL.getCode());
			uCarOrderRefundNotifyVoResp.setMessage(ResultEnum.FAIL.getMsg());
			log.info("退款成功后回调接口出参：{}", uCarOrderRefundNotifyVoResp);
			return uCarOrderRefundNotifyVoResp;
		}

	}
}
